home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / fsio / fsioLock.c < prev    next >
C/C++ Source or Header  |  1990-10-10  |  13KB  |  440 lines

  1. /* 
  2.  * fsLock.c --
  3.  *
  4.  *    File locking routines.  The Fsio_LockState data structure keeps info
  5.  *    about shared and exlusive locks.  This includes a list of waiting
  6.  *    processes, and a list of owning processes.  The ownership list
  7.  *    is used to recover from processes that exit before unlocking their
  8.  *    file, and to recover from hosts that crash running processes that
  9.  *    held file locks.  Synchronization over these routines is assumed
  10.  *    to be done by the caller via Fsutil_HandleLock.
  11.  *
  12.  * Copyright (C) 1986 Regents of the University of California
  13.  * All rights reserved.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /sprite/src/kernel/fsio/RCS/fsioLock.c,v 9.2 90/10/08 15:53:48 mendel Exp $ SPRITE (Berkeley)";
  18. #endif not lint
  19.  
  20.  
  21. #include <sprite.h>
  22. #include <fs.h>
  23. #include <fsutil.h>
  24. #include <fsioLock.h>
  25. #include <fsNameOps.h>
  26. #include <proc.h>
  27. #include <rpc.h>
  28. #include <net.h>
  29.  
  30. #include <stdio.h>
  31.  
  32. Boolean fsio_LockDebug = FALSE;
  33.  
  34. /*
  35.  * A  counter is incremented each time a process waits for a lock.
  36.  * This is used to track locking activity.
  37.  */
  38. int fsio_NumLockWaits = 0;
  39.  
  40. /*
  41.  * A list of lock owners is kept for files for error recovery.
  42.  * If a process exits without unlocking a file, or a host crashes
  43.  * that had processes with locks, then the locks are broken.
  44.  */
  45. typedef struct FsLockOwner {
  46.     List_Links links;        /* A list of these hangs from Fsio_LockState */
  47.     int hostID;            /* SpriteID of process that got the lock */
  48.     int procID;            /* ProcessID of owning process */
  49.     Fs_FileID streamID;        /* Stream on which lock call was made */
  50.     int flags;            /* IOC_LOCK_EXCLUSIVE, IOC_LOCK_SHARED */
  51. } FsLockOwner;
  52.  
  53. /*
  54.  *----------------------------------------------------------------------
  55.  *
  56.  * Fsio_LockInit --
  57.  *
  58.  *    Initialize lock state.
  59.  *
  60.  * Results:
  61.  *    None.
  62.  *
  63.  * Side effects:
  64.  *    Initializes the wait list, zeros out counters, etc.
  65.  *
  66.  *----------------------------------------------------------------------
  67.  */
  68.  
  69. void
  70. Fsio_LockInit(lockPtr)
  71.     register Fsio_LockState *lockPtr;    /* Locking state for a file. */
  72. {
  73.     List_Init(&lockPtr->waitList);
  74.     List_Init(&lockPtr->ownerList);
  75.     lockPtr->flags = 0;
  76.     lockPtr->numShared = 0;
  77. }
  78.  
  79. /*
  80.  *----------------------------------------------------------------------
  81.  *
  82.  * Fsio_IocLock --
  83.  *
  84.  *    Top-level locking/unlocking routine that handles I/O control
  85.  *    related byte swapping.  If the lock I/O control has been issued
  86.  *    from a client with a different archetecture the data block containing
  87.  *    the lock arguments has to be byte swapped.
  88.  *
  89.  * Results:
  90.  *    SUCCESS or FS_WOULD_BLOCK
  91.  *
  92.  * Side effects:
  93.  *    Lock or unlock the file, see Fsio_Lock and Fsio_Unlock.
  94.  *
  95.  *----------------------------------------------------------------------
  96.  */
  97.  
  98. ReturnStatus
  99. Fsio_IocLock(lockPtr, ioctlPtr, streamIDPtr)
  100.     register Fsio_LockState *lockPtr;    /* Locking state for a file. */
  101.     Fs_IOCParam *ioctlPtr;        /* I/O control parameter block */
  102.     Fs_FileID    *streamIDPtr;        /* ID of stream associated with lock */
  103. {
  104.     register Ioc_LockArgs *lockArgsPtr;
  105.     register ReturnStatus status = SUCCESS;
  106.     Ioc_LockArgs lockArgs;
  107.  
  108.     lockArgsPtr = (Ioc_LockArgs *) NIL;
  109.     if (ioctlPtr->format != mach_Format) {
  110.     int size = sizeof(Ioc_LockArgs);
  111.     int inSize = ioctlPtr->inBufSize;
  112.     int fmtStatus;
  113.     fmtStatus = Fmt_Convert("w4", ioctlPtr->format, &inSize, 
  114.             ioctlPtr->inBuffer, mach_Format, &size, 
  115.             (Address) &lockArgs);
  116.     if (fmtStatus != 0) {
  117.         printf("Format of ioctl failed <0x%x>\n", fmtStatus);
  118.         status = GEN_INVALID_ARG;
  119.     }
  120.     if (size != sizeof(Ioc_LockArgs)) {
  121.         status = GEN_INVALID_ARG;
  122.     } else {
  123.         lockArgsPtr = &lockArgs;
  124.     }
  125.     } else if (ioctlPtr->inBufSize < sizeof(Ioc_LockArgs)) {
  126.     status = GEN_INVALID_ARG;
  127.     } else {
  128.     lockArgsPtr = (Ioc_LockArgs *)ioctlPtr->inBuffer;
  129.     }
  130.     if (status == SUCCESS) {
  131.     if (ioctlPtr->command == IOC_LOCK) {
  132.         status = Fsio_Lock(lockPtr, lockArgsPtr, streamIDPtr);
  133.     } else {
  134.         status = Fsio_Unlock(lockPtr, lockArgsPtr, streamIDPtr);
  135.     }
  136.     }
  137.     return(status);
  138. }
  139.  
  140. /*
  141.  *----------------------------------------------------------------------
  142.  *
  143.  * Fsio_Lock --
  144.  *
  145.  *    Try to get a lock a stream.  If the lock is already held then
  146.  *    the caller is added to the waitlist for the lock and FS_WOULD_BLOCK
  147.  *    is returned.  Otherwise, the lock is marked as held and our
  148.  *    caller is put on the ownership list for the lock.
  149.  *
  150.  * Results:
  151.  *    SUCCESS or FS_WOULD_BLOCK
  152.  *
  153.  * Side effects:
  154.  *    If the lock is available then update the lock state of the file.
  155.  *
  156.  *----------------------------------------------------------------------
  157.  */
  158.  
  159. ReturnStatus
  160. Fsio_Lock(lockPtr, argPtr, streamIDPtr)
  161.     register Fsio_LockState *lockPtr;    /* Locking state for a file. */
  162.     Ioc_LockArgs *argPtr;        /* IOC_LOCK_EXCLUSIVE|IOC_LOCK_SHARED */
  163.     Fs_FileID    *streamIDPtr;        /* Stream that owns the lock */
  164. {
  165.     ReturnStatus status = SUCCESS;
  166.     register int operation = argPtr->flags;
  167.  
  168.     /*
  169.      * Attempt to lock the file.  Exclusive locks can't co-exist with
  170.      * any locks, while shared locks can exist with other shared locks.
  171.      */
  172.     if (operation & IOC_LOCK_EXCLUSIVE) {
  173.     if (lockPtr->flags & (IOC_LOCK_SHARED|IOC_LOCK_EXCLUSIVE)) {
  174.         status = FS_WOULD_BLOCK;
  175.     } else {
  176.         lockPtr->flags |= IOC_LOCK_EXCLUSIVE;
  177.     }
  178.     } else if (operation & IOC_LOCK_SHARED) {
  179.     if (lockPtr->flags & IOC_LOCK_EXCLUSIVE) {
  180.         status = FS_WOULD_BLOCK;
  181.     } else {
  182.         lockPtr->flags |= IOC_LOCK_SHARED;
  183.         lockPtr->numShared++;
  184.     }
  185.     } else {
  186.     status = GEN_INVALID_ARG;
  187.     }
  188.     if (status == SUCCESS) {
  189.     register FsLockOwner *lockOwnerPtr;
  190.     /*
  191.      * Put the calling process on the lock ownership list.
  192.      */
  193.     lockOwnerPtr = mnew(FsLockOwner);
  194.     List_InitElement((List_Links *)lockOwnerPtr);
  195.     lockOwnerPtr->hostID = argPtr->hostID;
  196.     lockOwnerPtr->procID = argPtr->pid;
  197.     if (streamIDPtr != (Fs_FileID *)NIL) {
  198.         lockOwnerPtr->streamID = *streamIDPtr;
  199.     } else {
  200.         lockOwnerPtr->streamID.type = -1;
  201.     }
  202.     lockOwnerPtr->flags = operation & (IOC_LOCK_EXCLUSIVE|IOC_LOCK_SHARED);
  203.     List_Insert((List_Links *)lockOwnerPtr,
  204.             LIST_ATREAR(&lockPtr->ownerList));
  205.     if (fsio_LockDebug) {
  206.         printf("Stream <%d,%d> locked %x by proc %x\n", streamIDPtr->major,
  207.         streamIDPtr->minor, lockOwnerPtr->flags, argPtr->pid);
  208.     }
  209.     } else if (status == FS_WOULD_BLOCK) {
  210.     Sync_RemoteWaiter wait;
  211.     /*
  212.      * Put the potential waiter on the file's lockWaitList.
  213.      */
  214.     if (argPtr->hostID > NET_NUM_SPRITE_HOSTS) {
  215.         printf( "Fsio_Lock: bad hostID %d.\n",
  216.               argPtr->hostID);
  217.     } else {
  218.         wait.hostID = argPtr->hostID;
  219.         wait.pid = argPtr->pid;
  220.         wait.waitToken = argPtr->token;
  221.         Fsutil_FastWaitListInsert(&lockPtr->waitList, &wait);
  222.         if (fsio_LockDebug) {
  223.         printf("Stream <%d,%d> Blocked, proc %x\n", streamIDPtr->major,
  224.             streamIDPtr->minor, argPtr->pid);
  225.         }
  226.     }
  227.     } else if (fsio_LockDebug) {
  228.     printf("Stream <%d,%d> locking error %x\n", streamIDPtr->major,
  229.             streamIDPtr->minor, status);
  230.     }
  231.     return(status);
  232. }
  233.  
  234. /*
  235.  *----------------------------------------------------------------------
  236.  *
  237.  * Fsio_Unlock --
  238.  *
  239.  *    Release a lock a stream.  The ownership list is checked here, but
  240.  *    the lock is released anyway.
  241.  *
  242.  * Results:
  243.  *    SUCCESS or FS_WOULD_BLOCK
  244.  *
  245.  * Side effects:
  246.  *    If the lock is available then update the lock state of the file.
  247.  *
  248.  *----------------------------------------------------------------------
  249.  */
  250.  
  251. ReturnStatus
  252. Fsio_Unlock(lockPtr, argPtr, streamIDPtr)
  253.     register Fsio_LockState *lockPtr;    /* Locking state for the file. */
  254.     Ioc_LockArgs *argPtr;    /* Lock flags and process info for waiting */
  255.     Fs_FileID    *streamIDPtr;    /* Verified against the lock ownership list */ 
  256. {
  257.     ReturnStatus status = SUCCESS;
  258.     register int operation = argPtr->flags;
  259.     register FsLockOwner *lockOwnerPtr;
  260.  
  261.     if (operation & IOC_LOCK_EXCLUSIVE) {
  262.     if (lockPtr->flags & IOC_LOCK_EXCLUSIVE) {
  263.         LIST_FORALL(&lockPtr->ownerList, (List_Links *)lockOwnerPtr) {
  264.         if ((lockOwnerPtr->procID == argPtr->pid) ||
  265.             (streamIDPtr != (Fs_FileID *)NIL &&
  266.              lockOwnerPtr->streamID.major == streamIDPtr->major &&
  267.              lockOwnerPtr->streamID.minor == streamIDPtr->minor &&
  268.              lockOwnerPtr->streamID.serverID == streamIDPtr->serverID)){
  269.             lockPtr->flags &= ~IOC_LOCK_EXCLUSIVE;
  270.             List_Remove((List_Links *)lockOwnerPtr);
  271.             free((Address)lockOwnerPtr);
  272.             break;
  273.         }
  274.         }
  275.         if (lockPtr->flags & IOC_LOCK_EXCLUSIVE) {
  276.         /*
  277.          * Oops, unlocking process didn't match lock owner.
  278.          */
  279.         if (!List_IsEmpty(&lockPtr->ownerList)) {
  280.             lockOwnerPtr =
  281.             (FsLockOwner *)List_First(&lockPtr->ownerList);
  282. #ifdef notdef
  283.             printf("Fsio_Unlock, non-owner <%x> unlocked, owner <%x>\n",
  284.             argPtr->pid, lockOwnerPtr->procID);
  285. #endif
  286.             List_Remove((List_Links *)lockOwnerPtr);
  287.             free((Address)lockOwnerPtr);
  288.         } else {
  289.             printf( "Fsio_Unlock, no lock owner\n");
  290.         }
  291.         lockPtr->flags &= ~IOC_LOCK_EXCLUSIVE;
  292.         }
  293.     } else {
  294.         status = FS_NO_EXCLUSIVE_LOCK;
  295.     }
  296.     } else if (operation & IOC_LOCK_SHARED) {
  297.     if (lockPtr->flags & IOC_LOCK_SHARED) {
  298.         status = FAILURE;
  299.         lockPtr->numShared--;
  300.         LIST_FORALL(&lockPtr->ownerList, (List_Links *)lockOwnerPtr) {
  301.         if ((lockOwnerPtr->procID == argPtr->pid) ||
  302.             (streamIDPtr != (Fs_FileID *)NIL &&
  303.              lockOwnerPtr->streamID.major == streamIDPtr->major &&
  304.              lockOwnerPtr->streamID.minor == streamIDPtr->minor &&
  305.              lockOwnerPtr->streamID.serverID == streamIDPtr->serverID)){
  306.             status = SUCCESS;
  307.             List_Remove((List_Links *)lockOwnerPtr);
  308.             free((Address)lockOwnerPtr);
  309.             break;
  310.         }
  311.         }
  312.         if (status != SUCCESS) {
  313.         /*
  314.          * Oops, unlocking process didn't match lock owner.
  315.          */
  316. #ifdef notdef
  317.         printf("Fsio_Unlock, non-owner <%x> did shared unlock\n",
  318.             argPtr->pid);
  319. #endif
  320.         status = SUCCESS;
  321.         }
  322.         if (lockPtr->numShared == 0) {
  323.         lockPtr->flags &= ~IOC_LOCK_SHARED;
  324.         }
  325.     } else {
  326.         status = FS_NO_SHARED_LOCK;
  327.     }
  328.     } else {
  329.     status = GEN_INVALID_ARG;
  330.     }
  331.     if (status == SUCCESS) {
  332.     /*
  333.      * Go through the list of waiters and notify them.  There is only
  334.      * a single waiting list for both exclusive and shared locks.  This
  335.      * means that exclusive lock attempts will be retried even if the
  336.      * shared lock count has not gone to zero.
  337.      */
  338.     Fsutil_FastWaitListNotify(&lockPtr->waitList);
  339.     if (fsio_LockDebug) {
  340.         printf("Stream <%d,%d> Unlocked %x, proc %x\n", streamIDPtr->major,
  341.         streamIDPtr->minor, operation, argPtr->pid);
  342.     }
  343.     }
  344.     return(status);
  345. }
  346.  
  347. /*
  348.  *----------------------------------------------------------------------
  349.  *
  350.  * Fsio_LockClose --
  351.  *
  352.  *    Check that the stream owns a lock on this file,
  353.  *    and if it does then break that lock.
  354.  *
  355.  * Results:
  356.  *    None.
  357.  *
  358.  * Side effects:
  359.  *    Cleans up the lock and frees owner information.
  360.  *
  361.  *----------------------------------------------------------------------
  362.  */
  363.  
  364. void
  365. Fsio_LockClose(lockPtr, streamIDPtr)
  366.     register Fsio_LockState *lockPtr;    /* Locking state for the file. */
  367.     Fs_FileID *streamIDPtr;        /* Stream being closed */
  368. {
  369.     register FsLockOwner *lockOwnerPtr;
  370.  
  371.     LIST_FORALL(&lockPtr->ownerList, (List_Links *)lockOwnerPtr) {
  372.     if (streamIDPtr != (Fs_FileID *)NIL &&
  373.         lockOwnerPtr->streamID.major == streamIDPtr->major &&
  374.         lockOwnerPtr->streamID.minor == streamIDPtr->minor &&
  375.         lockOwnerPtr->streamID.serverID == streamIDPtr->serverID) {
  376.         if (fsio_LockDebug) {
  377.         printf("Stream <%d,%d> Lock Closed %x\n",
  378.             streamIDPtr->major, streamIDPtr->minor,
  379.             lockOwnerPtr->flags);
  380.         }
  381.         lockPtr->flags &= ~lockOwnerPtr->flags;
  382.         List_Remove((List_Links *)lockOwnerPtr);
  383.         free((Address)lockOwnerPtr);
  384.         Fsutil_FastWaitListNotify(&lockPtr->waitList);
  385.         Fsutil_WaitListDelete(&lockPtr->waitList);
  386.         break;
  387.     }
  388.     }
  389. }
  390.  
  391. /*
  392.  *----------------------------------------------------------------------
  393.  *
  394.  * Fsio_LockClientKill --
  395.  *
  396.  *    Go through the list of lock owners and release any locks
  397.  *    held by processes on the given client.  This is called after
  398.  *    the client is assumed to be down.
  399.  *
  400.  * Results:
  401.  *    None.
  402.  *
  403.  * Side effects:
  404.  *    Releases locks held by processes on the client.
  405.  *
  406.  *----------------------------------------------------------------------
  407.  */
  408.  
  409. void
  410. Fsio_LockClientKill(lockPtr, clientID)
  411.     register Fsio_LockState *lockPtr;    /* Locking state for the file. */
  412.     int clientID;            /* SpriteID of crashed client. */
  413. {
  414.     register FsLockOwner *lockOwnerPtr;
  415.     register FsLockOwner *nextOwnerPtr;
  416.     register Boolean breakLock = FALSE;
  417.  
  418.     nextOwnerPtr = (FsLockOwner *)List_First(&lockPtr->ownerList);
  419.     while (!List_IsAtEnd(&lockPtr->ownerList, (List_Links *)nextOwnerPtr)) {
  420.     lockOwnerPtr = nextOwnerPtr;
  421.     nextOwnerPtr = (FsLockOwner *)List_Next((List_Links *)lockOwnerPtr);
  422.  
  423.     if (lockOwnerPtr->hostID == clientID) {
  424.         breakLock = TRUE;
  425.         lockPtr->flags &= ~lockOwnerPtr->flags;
  426.         if (fsio_LockDebug) {
  427.         printf("Stream <%d,%d> Lock Broken %x Client %d\n",
  428.             lockOwnerPtr->streamID.major, lockOwnerPtr->streamID.minor,
  429.             lockOwnerPtr->flags, clientID);
  430.         }
  431.         List_Remove((List_Links *)lockOwnerPtr);
  432.         free((Address)lockOwnerPtr);
  433.     }
  434.     }
  435.     if (breakLock) {
  436.     Fsutil_FastWaitListNotify(&lockPtr->waitList);
  437.     }
  438. }
  439.  
  440.